package user

import (
	"cache"
	"errors"
	"message"
	"msgsign"
	"net"
	"runtime"
	"strconv"
	"time"
//	"nethandle"
	//	"log"
)

type UserInfo struct {
	IsLogin   bool
	LoginTime time.Time
	UserIp    string
	Conn      net.Conn
	Userid    string
	Keeptime  int64
}

func (ui *UserInfo) SetUserId(userid string) {
	ui.Userid = userid
	uc := cache.GetConnCache()
	uc.Add(userid, ui)
	cache.GetUserList().Add(userid)

}
func (ui *UserInfo) SetKeeptime(time int64) {
	ui.Keeptime = time
}

func (ui *UserInfo) Destroy() {
	if len(ui.Userid) > 0 {
		uc := cache.GetConnCache()
		u := uc.Get(ui.Userid)

		if u != nil {
			ss, _ := u.(*UserInfo)
			if ui.Conn == ss.Conn {
				uc.Delete(ui.Userid)
				cache.GetUserList().Delete( ui.Userid)
			}
		}

		ui.Conn.Close()
		ui.Conn = nil
	}
}

func (ui *UserInfo) Live() error {
	var msg message.Message
	msg.Heads = []*message.Head{&message.Head{msgsign.TYPR, msgsign.LIVE}}
	return ui.SystemResult(message.MessageToByte(&msg))
}

func SystemSendMessage(userid string, msg string) error {
	var mes message.Message
	mes.Heads = []*message.Head{&message.Head{msgsign.TYPR, msgsign.MESSAGE}, &message.Head{msgsign.TO, userid}, &message.Head{msgsign.FROM, msgsign.SYSTEM}}
	mes.Body = []byte(msg)
	return SendMessageByUserid(userid, message.MessageToByte(&mes))
}

func (ui *UserInfo) SystemResult(result []byte) error {
	return message.SendMessageByConn(ui.Conn, result)
}

func (ui *UserInfo) SendMsgToUser(userid string, msg *message.Message) error {
	return SendMessageByUserid(userid, message.MessageToByte(msg))
}

func SendMessageByUserid(userid string, msg []byte) error {
	uc := cache.GetConnCache()
	u := uc.Get(userid)
	if u == nil {
		return errors.New(msgsign.USER_OFFLINE)
	}
	ss, ok := u.(*UserInfo)
	if ok == false {
		return errors.New(msgsign.USER_ERROR)
	} else {
		err := message.SendMessageByConn(ss.Conn, msg)
		if err != nil {
			uc.Delete(userid)
		}
		return err
	}
}

func (ui *UserInfo) SendMsg(msg *message.Message) error {

	to := msg.GetHeadValue(msgsign.TO)
	if len(to) == 0 {
		return errors.New(msgsign.NO_USER)
	} else {
		return ui.SendMsgToUser(to, msg)
	}
}

func (ui *UserInfo) Login(msg *message.Message) error {

	username := msg.GetHeadValue(msgsign.USERNAME)
	uc := cache.GetConnCache()
	u := uc.Get(username)
	if u != nil {
		ss, ok := u.(*UserInfo)
		if ok == false {
			uc.Delete(username)
		} else {
			if ss.Conn != nil {
				uc.Delete(username)
				message.SendMessageByConn(ss.Conn, message.Logout())
				ss.Conn.Close()
			}
		}

	}

	if len(username) > 0 {
		ui.SetUserId(username)
		return ui.LoginResult(msgsign.SUCCESS)
	} else {
		ui.LoginResult(msgsign.FAIL)
		return errors.New(msgsign.LOGIN_FAIL)
	}
}

func (ui *UserInfo) MessageResult(mesg *message.Message, result string) error {

	msgid := mesg.GetHeadValue(msgsign.MESSAGEID)
	var msg message.Message
	msg.Heads = []*message.Head{&message.Head{msgsign.TYPR, msgsign.TRACK}, &message.Head{msgsign.MESSAGEID, msgid}, &message.Head{msgsign.RESULT, result}}
	return ui.SystemResult(message.MessageToByte(&msg))
}

func (ui *UserInfo) LoginResult(result string) error {
	var msg message.Message
	msg.Heads = []*message.Head{&message.Head{msgsign.TYPR, msgsign.LOGIN}, &message.Head{msgsign.STATUS, result}}
	return ui.SystemResult(message.MessageToByte(&msg))
}


func (ui *UserInfo) GetMessage(conn net.Conn) ([]byte, error) {

	data := make([]byte, 0)
	for {
		buf := make([]byte, msgsign.BufLength)
		if ui.Keeptime > 1000 {
			conn.SetReadDeadline((time.Now().Add(time.Duration(ui.Keeptime) * time.Millisecond)))
		} else {
			conn.SetReadDeadline((time.Now().Add(time.Second * 70)))
		}
		n, err := conn.Read(buf)
		runtime.Gosched()
		if err != nil {
			conn.Close()
			return []byte(""), errors.New(msgsign.NET_ERROR)
		}
		data = append(data, buf[:n]...)
		if data[n-4] == '-' && data[n-3] == '\r' && data[n-2] == '\n' && data[n-1] == '-' {
			break
		}
	}

	return data, nil
}
func (ui *UserInfo) HandleLogin(value *message.Message) error {
	err := ui.Login(value)
	if err != nil {
		return err
	} else {
		time_ := value.GetHeadValue(msgsign.TIME)
		if time_ != "" {
			t, err := strconv.Atoi(time_)
			if err == nil {
				ti := (t + 10000)
				ui.SetKeeptime(int64(ti))
			} else {
				ui.SetKeeptime(120000)
			}
		}
	}
	return nil
}

func (ui *UserInfo) HandleLive(value *message.Message) {
	if ui.Keeptime == 0 {
		time_ := value.GetHeadValue(msgsign.TIME)
		if time_ != "" {
			t, err := strconv.Atoi(time_)
			if err == nil {
				var ti = (t + 10000)
				ui.SetKeeptime(int64(ti))
				ui.Conn.SetReadDeadline((time.Now().Add(time.Duration(ti) * time.Millisecond)))
			}
		}
	}
	ui.Live()
}

func (ui *UserInfo) HandleMessage(value *message.Message) error {
//	panic(55)
	type_ := value.GetHeadValue(msgsign.TYPR)
	switch type_ {
	case msgsign.LOGIN:
		{
			err := ui.HandleLogin(value)
			if err != nil {
				return err
			}

		}
	case msgsign.MESSAGE:
		{
			err := ui.SendMsg(value)
			if err != nil {
				ui.MessageResult(value, err.Error())
			} else {
				ui.MessageResult(value, msgsign.SUCCESS)
			}

		}
	case msgsign.LIVE:
		{
			ui.HandleLive(value)
		}
	default:
		{
			return errors.New(msgsign.DATA_ERROR)
		}
	}
	runtime.Gosched()
	return nil
}

func errorHandle(ui *UserInfo) {
	if err := recover(); err != nil {
		if ui != nil {
			ui.Destroy()
		}
	}
}


func (ui *UserInfo) HandleConn() error {
	defer errorHandle(ui)
	ui.LoginResult(msgsign.START)
	for {
		bs, err := ui.GetMessage(ui.Conn)
		if err != nil {
			return err
		}
		msgs := message.BytesToMessage(bs)
		for _, value := range msgs {
			err := ui.HandleMessage(value)
			if err != nil {
				return err
			}
		}
	}
	return errors.New(msgsign.NET_ERROR)
}
